﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace CreateDefect.Domain
{
    /// <summary>
    /// Connection to Quality Center
    /// </summary>
    public class QCConnection : Connection
    {
        #region Methods
        /// <summary>
        /// Connects to QC database and authenticates 
        /// </summary>
        /// <param name="url">URL for QC server</param>
        /// <param name="username">Username as string</param>
        /// <param name="password">Password as string</param>
        /// <returns>Returns Boolean</returns>
        public bool Authenticate(string url, string username, string password)
        {
            try
            {
                TDConnection = new TDAPIOLELib.TDConnection();

                TDConnection.InitConnectionEx(url);
                TDConnection.Login(username, password);

                return true;
            }
            catch (Exception ex) { throw ex; }
        }

        /// <summary>
        /// Gets the visible domains for the user
        /// </summary>
        /// <returns>Returns array</returns>
        public List<string> Domains()
        {
            try
            {
                List<string> domainList = new List<string>();

                foreach (string s in TDConnection.VisibleDomains)
                    domainList.Add(s);

                return domainList;
            }
            catch (Exception ex) { throw ex; }
        }

        /// <summary>
        /// Gets the visible projects for the user
        /// </summary>
        /// <param name="domain"></param>
        /// <returns>Returns array</returns>
        public List<string> Projects(string domain)
        {
            try
            {
                List<string> projectList = new List<string>();

                TDAPIOLELib.List tdcList = TDConnection.get_VisibleProjects(domain);

                foreach (string s in tdcList)
                    projectList.Add(s);

                return projectList;

            }
            catch (Exception ex) { throw ex; }
        }

        /// <summary>
        /// Logs into Quality Center
        /// </summary>
        /// <param name="domain">Selected domain as string</param>
        /// <param name="project">Selected project as string</param>
        /// <returns>Returns Boolean</returns>
        public bool Login(string domain, string project)
        {
            try
            {
                TDConnection.Connect(domain, project);

                return true;
            }
            catch (Exception ex) { throw ex; }
        }

        /// <summary>
        /// Returns True if disconnect from project is successful
        /// </summary>
        /// <returns>Returns Boolean</returns>
        public bool Disconnect()
        {
            try
            {
                TDConnection.Disconnect();
                return true;
            }
            catch (Exception ex) { throw ex; }
        }

        /// <summary>
        /// Returns True if logout is successful
        /// </summary>
        /// <returns>Returns Boolean</returns>
        public bool Logout()
        {
            try
            {
                TDConnection.Disconnect();
                TDConnection.Logout();
                TDConnection.ReleaseConnection();
                return true;
            }
            catch (Exception ex) { throw ex; }
        }

        /// <summary>
        /// Gets a list of all fields in the table
        /// </summary>
        /// <param name="ShowProtected">If true only return fields shown on the UI</param>
        /// <returns>Dictionary key: UI label, value: database column name</returns>
        public List<string> AllUserFields(string TableName)
        {
            try
            {
                TDAPIOLELib.List list = TDConnection.Fields[TableName];

                List<string> fields = new List<string>();
                // go through each field (column in table)
                foreach (TDAPIOLELib.TDField f in list)
                {
                    // get column properties
                    TDAPIOLELib.FieldProperty fp = f.Property;

                    // if the field is shown on the UI and required
                    if (fp.IsRequired == true)
                        fields.Add(fp.UserLabel);
                }
                return fields;
            }
            catch (Exception ex) { throw ex; }
        }

        /// <summary>
        /// Returns the column type associated with a UserField
        /// </summary>
        /// <param name="TableName"></param>
        /// <param name="UserField"></param>
        /// <returns></returns>
        public string FieldType(string TableName, string UserField)
        {
            try
            {
                TDAPIOLELib.List list = TDConnection.Fields[TableName];

                // go through each field (column in table)
                foreach (TDAPIOLELib.TDField f in list)
                {
                    // get column properties
                    TDAPIOLELib.FieldProperty fp = f.Property;
                    

                    // if the field is shown on the UI and required
                    if (fp.UserLabel == UserField)
                        return fp.DBColumnType;
                }
                return null;
            }
            catch (Exception ex) { throw ex; }
        }

        /// <summary>
        /// Returns the column name associated with a UserField
        /// </summary>
        /// <param name="TableName"></param>
        /// <param name="UserField"></param>
        /// <returns></returns>
        public string FieldColumnName(string TableName, string UserField)
        {
            try
            {
                TDAPIOLELib.List list = TDConnection.Fields[TableName];

                // go through each field (column in table)
                foreach (TDAPIOLELib.TDField f in list)
                {
                    // get column properties
                    TDAPIOLELib.FieldProperty fp = f.Property;


                    // if the field is shown on the UI and required
                    if (fp.UserLabel == UserField)
                        return fp.DBColumnName;
                }
                return null;
            }
            catch (Exception ex) { throw ex; }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="Table"></param>
        /// <param name="UserField"></param>
        /// <returns></returns>
        public List<string> FieldList(string Table, string UserField)
        {
            try
            {
                TDAPIOLELib.Customization cust = TDConnection.Customization;

                TDAPIOLELib.CustomizationFields fields = cust.Fields;
                TDAPIOLELib.CustomizationField aField = fields.Field[Table, UserField];

                TDAPIOLELib.CustomizationList fieldList = aField.List;
                if (fieldList != null)
                {
                    TDAPIOLELib.CustomizationListNode listRoot = fieldList.RootNode;
                    TDAPIOLELib.List nodes = listRoot.Children;

                    List<string> values = new List<string>();
                    foreach (TDAPIOLELib.CustomizationListNode n in nodes)
                        values.Add(n.Name);

                    return values;
                }

                return null;
            }
            catch (Exception ex) { throw ex; }
        }
        #endregion

        #region Properties
        /// <summary>
        /// Returns the username connected to quality center
        /// </summary>
        public string UserName
        {
            get { return TDConnection.UserName; }
        }

        /// <summary>
        /// Stores the user password
        /// </summary>
        public string UserPassword
        { 
            get; set; 
        }

        /// <summary>
        /// Returns name of the connected Domain
        /// </summary>
        public string ConnectedDomain
        {
            get { return this.TDConnection.DomainName; }
        }

        /// <summary>
        /// Returns name of the connected Project
        /// </summary>
        public string ConnectedProject
        {
            get { return TDConnection.ProjectName; }
        }

        /// <summary>
        /// Returns true if connected to the server
        /// </summary>
        public bool ServerConnected
        {
            get
            {
                try { return this.TDConnection.Connected; }
                catch { return false; }
            }
        }

        /// <summary>
        /// Returns true if connected to the server and a project
        /// </summary>
        public bool ProjectConnected
        {
            get
            {
                try { return this.TDConnection.Connected; }
                catch { return false; }
            }
        }
        #endregion

        #region Classes
        /// <summary>
        /// New defect
        /// </summary>
        /// <returns>Empty, defect</returns>
        public QCDefect QCDefect()
        {
            return new QCDefect(this.TDConnection);
        }

        /// <summary>
        /// Existing defect by ID
        /// </summary>
        /// <param name="DefectId">Defect Id</param>
        /// <returns>Existing defect</returns>
        public QCDefect QCDefect(int DefectId)
        {
            return new QCDefect(this.TDConnection, DefectId);
        }

        /// <summary>
        /// List of filtered defects
        /// </summary>
        /// <param name="Filter">Key is the bug field, value is the value of the field</param>
        /// <returns>List of defects</returns>
        public List<QCDefect> QCDefect(Dictionary<string, dynamic> Filter)
        {
            try
            {
                TDAPIOLELib.BugFactory bFact = (TDAPIOLELib.BugFactory)this.TDConnection.BugFactory;
                TDAPIOLELib.TDFilter filter = (TDAPIOLELib.TDFilter)bFact.Filter;
                foreach (var f in Filter)
                    filter[f.Key] = f.Value;

                TDAPIOLELib.List filtered = filter.NewList();
                List<QCDefect> defects = new List<QCDefect>();

                foreach (TDAPIOLELib.Bug b in filtered)
                    defects.Add(new QCDefect(this.TDConnection, (int)b.ID));

                return defects;
            }
            catch (Exception ex) { throw ex; }

        }
        #endregion
    }

    /// <summary>
    /// Base class for Quality Center connection
    /// </summary>
    public abstract class Connection
    {
        public Connection()
        {
            try
            {
                QCConnection conn = (QCConnection)HttpContext.Current.Session["QCConnection"];

                // if connection already exists, assign it
                if (conn != null)
                    this.TDConnection = (TDAPIOLELib.TDConnection)conn.TDConnection;
            }
            catch (Exception ex) { throw ex; }
        }

        internal TDAPIOLELib.TDConnection TDConnection { get; set; }
    }
}